/**
 * stream.h
 *
 *  Created on: 2019-09-05
 *      Author: chenshisheng
 */

#ifndef STREAM_STREAM_H_
#define STREAM_STREAM_H_

#include "main.h"

BEGIN_C_DECLS
typedef int (*Stream_Put_t)(void *stream, unsigned char b);
typedef int (*Stream_Get_t)(void *stream, unsigned char *pb);
typedef void (*Stream_Flush_t)(void *stream);
typedef int (*Stream_Tx_t)(void *stream, const void *data, unsigned int size);

typedef struct
{
    Stream_Put_t put;
    Stream_Get_t get;
    Stream_Flush_t flush;
#ifdef CMSIS_OS
    osMutexId_t mutexRead, mutexWrite;
#endif
}Stream_t;

typedef struct
{
    Stream_t *stream;
    char tail;
}Stream_LineSignal_t;

int Stream_Init(Stream_t *stream, Stream_Put_t put, Stream_Get_t get, Stream_Flush_t flush, bool useMutex);
void Stream_DeInit(Stream_t *stream);

#if CMSIS_OS
static inline osStatus Stream_AcquireWrite(void *stream)
{
    Stream_t *s = stream;

    return s->mutexWrite ? osMutexAcquire(s->mutexWrite, osWaitForever) : osOK;
}

static inline osStatus Stream_ReleaseWrite(void *stream)
{
    Stream_t *s = stream;

    return s->mutexWrite ? osMutexRelease(s->mutexWrite) : osOK;
}

static inline osStatus Stream_AcquireRead(void *stream)
{
    Stream_t *s = stream;

    return s->mutexRead ? osMutexAcquire(s->mutexRead, osWaitForever) : osOK;
}

static inline osStatus Stream_ReleaseRead(void *stream)
{
    Stream_t *s = stream;

    return s->mutexRead ? osMutexRelease(s->mutexRead) : osOK;
}

#else
#   define Stream_AcquireWrite(stream) (void)0
#   define Stream_ReleaseWrite(stream) (void)0
#   define Stream_AcquireRead(stream)  (void)0
#   define Stream_ReleaseRead(stream)  (void)0
#endif

static inline int Stream_Put(void *stream, unsigned char b)
{
    Stream_t *s = (Stream_t *)stream;

    return s->put(stream, b);
}

static inline int Stream_Get(void *stream, unsigned char *pb)
{
    Stream_t *s = (Stream_t *)stream;

    return s->get(stream, pb);
}

static inline void Stream_Flush(void *stream)
{
    Stream_t *s = (Stream_t *)stream;

    Stream_AcquireWrite(s);
    s->flush(stream);
    Stream_ReleaseWrite(s);
}

int Stream_Write(void *stream, const void *data, unsigned int size);
int Stream_Read(void *stream, void *data, unsigned int size);
int Stream_ReadUntil(void *stream, char buf[], unsigned int maxSize, char till);

END_C_DECLS
#endif /* STREAM_STREAM_H_ */
